<template>
  <div class="asset-tree-layout" v-loading="loading">
    <div class="asset-top-lay">
      <TableSearchWidget ref="refSearch" :search="searchParams">
        <template v-slot:searchTail>
          <div style="display: flex; flex-direction: row; justify-content: center">
            <el-input class="asset-tree-filter" v-model="filterText" size="small"
                      :placeholder="placeHolder" clearable/>
            <el-button icon="refresh" type="success" @click="loadAssets">
              筛选
            </el-button>
            <el-button v-if="!isLoginUser && hasAssign" type="primary" icon="Check" @click="save" style="margin: 0 8px 0 24px;">
              保存
            </el-button>
            <el-button v-if="!isLoginUser && hasAssign" @click="cancel" type="danger" icon="Close" style="margin: 0 8px 0 16px;">
              取消
            </el-button>
            <el-checkbox v-model="showExpandAll" @change="toggleExpandAll" style="margin-left: 16px;">
              展开/折叠
            </el-checkbox>
            <slot name="tail"/>
          </div>
        </template>
      </TableSearchWidget>
      <div v-if="props.comment" class="comment-lay">
        <el-icon color="#6b66d4" style="margin-right: 2px;">
          <QuestionFilled/>
        </el-icon>
        {{ props.comment }}
      </div>
      <div style="flex: 1"/>
    </div>
    <el-tree
        class="asset-tree"
        ref="refAssetTree"
        :data="data"
        show-checkbox
        node-key="id"
        :check-strictly="true"
        :default-expanded-keys="[2, 3]"
        :default-checked-keys="[5]"
        :props="{ class: assetTreeNodeClass, label: 'name', disabled: disableNode}"
        :filter-node-method="filterNode"
        :default-expand-all="showExpandAll">
      <template #default="{ node, data }">
        <div @mouseleave="mouseleave(data)" @mouseover="mouseover(data)" style="width: 100%;">
          <span>{{ node.label }}</span>
          <el-button v-if="data.showBtn && data.children && data.children.length > 0"
                     size="small" plain style="margin-left: 16px;" @click.stop="onClickTree(data)">
            {{ data.allSel ? '取消' : '全选' }}
          </el-button>
        </div>
      </template>
    </el-tree>
  </div>
</template>

<script setup lang="ts">

import {computed, nextTick, onMounted, ref, watch} from "vue";
import {QuestionFilled} from "@element-plus/icons-vue";
import {msgError, msgInfo} from "@/utils/InfoUtil";
import {runMethod} from "@/utils/DateUtil";
import {useTerminal} from "@/utils/sop/UseTerminal";
import TableSearchWidget from "@/widget/TableSearchWidget.vue";
import {hasPermit} from "@/utils/sop/PermitUtil";
import {filterTreeList} from "@/utils/SystemUtil";
import {currentNames} from "@/stores/conf";
import {useStore} from "@/stores";

const data = ref();
const loading = ref();
const refAssetTree = ref();
const hasAsset = ref();
const filterText = ref('')

const props = withDefaults(defineProps<{
  entry?: any,
  name: string,
  path?: any,
  readonly?: boolean,
  product?: boolean,
  expandAll?: boolean,
  comment?: string,
  blankTip?: string,
  assignAssets?: any,
  loadHoldAsset?: any,
  loadAssetData?: any,
  loadHoldOtherAsset?: any,
}>(), {});

const holdItems = ref([]);
const holdOtherItems = ref([]);
const showExpandAll = ref(props.expandAll);

const {productCode} = useTerminal(props.name)
const currentTerminalCode = ref(productCode())

const searchParams = ref([]);

const store: any = useStore();

const isLoginUser = computed(() => {
  if (currentNames.PLAT_USER != props.entry.name) {
    return false;
  } else {
    const currUser: any = store.getCurrent(props.entry.name);
    const loginUser: any = store.getUser();
    return currUser && currUser.item && loginUser && loginUser.userId == currUser.item.id;
  }
});

const hasAssign: any = computed(() => {
  return !props.readonly && hasPermit('platform:user:assign-role');
})

const toggleExpandAll = (type: any) => {
  if (type) {
    showExpandAll.value = true;
    Object.values(refAssetTree.value.store.nodesMap).forEach((v: any) => v.expand());
    return;
  }
  showExpandAll.value = false;
  Object.values(refAssetTree.value.store.nodesMap).forEach((v: any) => v.collapse());
};

const disableNode = (data: any, node: any) => {
  return data.noAuth == 1;
}

const calcNodeAllSel = (items: any, data: any): boolean => {
  if (items.indexOf(data.id) == -1) {
    return false;
  } else {
    if (data.children && data.children.length > 0) {
      let result: boolean = true;
      for (const item of data.children) {
        result = calcNodeAllSel(items, item);
        if (!result) {
          break;
        }
      }
      return result;
    } else {
      return true;
    }
  }
}

const nodeAllSel = (data: any) => {
  const checkedItems: any = getOriCheckedAssets();
  data.allSel = calcNodeAllSel(checkedItems, data);
}

const selAllNode = (items: any, data: any) => {
  if (items.indexOf(data.id) == -1 && data.noAuth != 1) {
    items.push(data.id);
  }
  if (data.children && data.children.length > 0) {
    for (const item of data.children) {
      selAllNode(items, item)
    }
  }
}

const unselectAllNode = (items: any, data: any) => {
  const index = items.indexOf(data.id);
  if (index !== -1) {
    items.splice(index, 1);
  }
  if (data.children && data.children.length > 0) {
    for (const item of data.children) {
      unselectAllNode(items, item)
    }
  }
}

const onClickTree = (data: any) => {
  const checkedItems: any = getOriCheckedAssets();
  if (!data.allSel) {
    selAllNode(checkedItems, data);
  } else {
    unselectAllNode(checkedItems, data);
  }
  setCheckedItems(checkedItems);
  data.allSel = !data.allSel;
}

const mouseleave = (data: any) => {
  data.showBtn = false;
}

//树控件鼠标移入事件
const mouseover = (data: any) => {
  nodeAllSel(data);
  data.showBtn = true;
}

watch(filterText, (val) => {
  refAssetTree.value!.filter(val)
})

const placeHolder = computed(() => {
  return `请输入${props.name}名称`;
})

const setCheckedItems = (selItems: string[]) => {
  refAssetTree.value!.setCheckedKeys(selItems, false);
}

const getOriCheckedAssets = () => {
  return refAssetTree.value!.getCheckedKeys(false) || [];
}

const getCheckedAssets = () => {
  const checkAsset: any = [];
  const selItems = refAssetTree.value!.getCheckedKeys(false);
  selItems.forEach((item: any) => {
    checkAsset.push({
      id: item,
    })
  })
  return checkAsset;
}

const retCheckedItems = () => {
  const selItems: any = [];
  holdItems.value.forEach((item: any) => {
    selItems.push(item.id);
  });
  setCheckedItems(selItems);
}

const filterNode = (value: string, data: any) => {
  if (!value) {
    return true;
  } else {
    return data.name.includes(value)
  }
}

const isSaveSel = (id: string) => {
  return holdItems.value.find(item => item.id === id);
}

const isOtherSel = (id: string) => {
  return holdOtherItems.value.find(item => item.id === id);
}

const assetTreeNodeClass = (data: any, node: any) => {
  const saveSel = isSaveSel(data.id);
  const otherSel = isOtherSel(data.id);

  // 无操作权限
  if (data.noAuth == 1) {
    return 'asset-no-auth';
  } else if (node.checked) {
    if (!saveSel) {
      return 'asset-add-sel';
    } else if (otherSel) {
      return 'asset-other-sel';
    }
  } else if (saveSel) {
    return otherSel ? 'asset-other-sel' : 'asset-del-sel';
  } else if (otherSel) {
    return 'asset-other-sel';
  }
}

const refreshHoldAsset = async () => {
  holdItems.value = await props.loadHoldAsset() || [];
  holdOtherItems.value = await props.loadHoldOtherAsset() || [];
}

const loadData = async (params: any) => {
  const result = await props.loadAssetData({
    ...params,
    productCode: getProductCode(),
  });

  if (result && result.code === 0 && result.data && result.data.length > 0) {
    hasAsset.value = true;
    data.value = filterTreeList(result.data, (item: any) => {
      return item.noAuth != 1 ? 1 : 2;
    });
    await refreshHoldAsset();
    await nextTick(() => retCheckedItems());
    return result;
  } else {
    data.value = [];
    hasAsset.value = false;
  }
}

const loadAssets = async () => {
  loading.value = true;
  await runMethod({}, async () => {
    await loadData({});
  })
  loading.value = false;
}

const save = async () => {
  loading.value = true;

  await runMethod({}, async () => {
    const selAssets = getCheckedAssets();
    const result = await props.assignAssets(selAssets);

    if (result && result.code === 0) {
      msgInfo(`保存${props.name}成功！`);
      await loadData({});
    } else {
      msgError(result ? result.message : `保存${props.name}失败！`);
    }
  });

  loading.value = false;
}

const cancel = () => {
  retCheckedItems();
}

const refreshData = async () => {
  await loadData({});
}

const refresh = async () => {
  await refreshData();
}

const refreshHoldOtherAsset = async () => {
  holdOtherItems.value = await props.loadHoldOtherAsset() || [];
}

const getProductCode = () => {
  return props.product ? currentTerminalCode.value : productCode()
}

const expandAllTree = () => {
  showExpandAll.value = !showExpandAll.value;
}

onMounted(() => {
})

defineExpose({
  refresh,
  expandAllTree,
  getProductCode,
  refreshHoldOtherAsset,
})

</script>

<style scoped>
.el-form-item-class .el-form-item__label {
  font-size: 12px;
}

.asset-tree-layout {
  display: flex;
  flex: 1;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

.comment-lay {
  display: flex;
  align-items: center;
  margin-left: 32px;
  color: #6b66d4;
  font-size: 12px;
}

.assign-btn {
  margin: 16px 0;
}

.asset-top-lay {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  padding: 16px 16px 24px 16px;
  border-bottom: 1px solid #e4e7ed;
}

.asset-tree {
  margin: 16px;
}

.asset-tree-filter {
  height: 32px;
  margin-right: 16px;
  width: 160px;
}

.asset-tree:deep(.asset-add-sel > .el-tree-node__content) {
  color: #626aef;
}

:deep(.asset-del-sel > .el-tree-node__content) {
  color: #FF5500;
}

:deep(.asset-no-auth > .el-tree-node__content) {
  color: #A1A1A1;
}

:deep(.asset-other-sel > .el-tree-node__content) {
  color: #409eff;
}

.asset-tree:deep(.el-tree-node.asset-leaf > .el-tree-node__children) {
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
}

.asset-tree:deep(.asset-leaf > .el-tree-node__children > div) {
  text-align: left;
  padding: 0 4px 0 0;
  margin: 0;
}

</style>
